package com.xcity.game.combat.listener.combat;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.slf4j.Logger;

import com.xcity.db.entity.Employee;
import com.xcity.db.entity.Employee.State;
import com.xcity.db.entity.Player;
import com.xcity.game.ISystem;
import com.xcity.game.battle.pve.PVEManager;
import com.xcity.game.battle.pve.PVEStage;
import com.xcity.game.battle.pve.PVEStageDropListener;
import com.xcity.game.battle.pve.PVEUtils;
import com.xcity.game.battle.pve.template.StageTemplate;
import com.xcity.game.combat.Combat;
import com.xcity.game.combat.Combat.Type;
import com.xcity.game.combat.CombatException;
import com.xcity.game.combat.CombatService;
import com.xcity.game.combat.CombatTeam;
import com.xcity.game.combat.Round;
import com.xcity.game.combat.builder.DefaultCombatBuilder;
import com.xcity.game.combat.listener.CombatListener;
import com.xcity.game.combat.listener.combat.ResStageCombatListener.RewardInfo;
import com.xcity.game.combat.unit.CombatUnit;
import com.xcity.game.combat.unit.impl.NpcCombatUnit;
import com.xcity.game.common.Cause;
import com.xcity.game.common.GameStaticConfig;
import com.xcity.game.common.MessageConst;
import com.xcity.game.employee.EmployeeService;
import com.xcity.game.employee.template.EmployeeTemplate;
import com.xcity.game.event.GameEvents;
import com.xcity.game.formation.Formation;
import com.xcity.game.item.DropGroupTemplate;
import com.xcity.game.item.drop.Drop;
import com.xcity.game.item.drop.impl.ItemDrop;
import com.xcity.game.item.drop.listener.ItemDropListener;
import com.xcity.game.npc.NpcTemplate;
import com.xcity.pomelo.push.msg.CombatEndPush;
import com.xcity.pomelo.request.CombatInfoRequest;
import com.xcity.pomelo.request.CombatPVERequest;
import com.xcity.pomelo.response.CombatInfoResponse;
import com.xcity.pomelo.response.CombatInfoResponse.TeamBuilder;
import com.xcity.pomelo.response.CombatResponse;
import com.xcity.pomelo.response.PVEStageV2Response.StarInfo;

import naga.x.App;
import naga.x.game.template.TemplateService;
import naga.x.game.time.TimeUpdater;
import naga.x.net.Packet;
import naga.x.net.Session;

public class PVECombatListener implements CombatListener {

	protected Player player;
	protected List<Employee> employees;
	protected PVEStage stage;
	protected static final Logger LOG = CombatService.LOG;
	protected long creatTime;
	
	static List<EmployeeTemplate> employeesForFresher; // 新手引导玩家使用固定的员工
	static {
		employeesForFresher = new ArrayList<EmployeeTemplate>(4);
		TemplateService service = App.getApp().getServiceManager().get(TemplateService.class);
		employeesForFresher.add(service.get(EmployeeTemplate.class, 90006));
		employeesForFresher.add(service.get(EmployeeTemplate.class, 90007));
		employeesForFresher.add(service.get(EmployeeTemplate.class, 90008));
		employeesForFresher.add(service.get(EmployeeTemplate.class, 90009));
	}
	
	private void init(int stageId) throws CombatException {
		if (stageId < 0) { // 新手引导关卡
			initForFresher();
			return;
		}
		// 初始化关卡数据
		stage = player.getPveStages().getStage(stageId);
		if (stage == null) {
			throw new CombatException(MessageConst.PVE_STAGE_NO_STAGE);
		}
		if (stage.getTemplate().getLevelLimit() > player.getLevel()) {
			throw new CombatException(MessageFormat.format(MessageConst.PVE_STAGE_LEVEL_LIMIT, stage.getTemplate().getLevelLimit()));
		}
//		PVEStage previous = stageIndex > 0 ? stages.get(stageIndex - 1) : null;
//		if (previous != null && previous.getStar() <= 0) {
//			throw new CombatException(MessageConst.PVE_PREVIOUS_STAGE_NOT_PASS);
//		}
		String passName = player.getPveStages().proviousName(stage);
		if(passName != null){
			throw new CombatException(MessageFormat.format(MessageConst.PVE_PREVIOUS_STAGE_NOT_PASS_NAME, passName));
		}
		// 初始化员工数据
//		long[] employeeIds = CombatUtils.getCombatFormation(player, true);
		employees = Arrays.asList(player.getFormations().get(Formation.TYPE_NORMAL).getUnits());//new ArrayList<Employee>(employeeIds.length);
//		for (long eid : employeeIds) {
//			Employee e = eid != 0L ? player.getEmployees().get(eid) : null;
//			employees.add(e);
//		}
	}
	
	private void initForFresher() {
		stage = new PVEStage(StageTemplate.FRESH_TEMPLATE);
		List<EmployeeTemplate> templates = employeesForFresher;
		employees = new ArrayList<Employee>(templates.size());
		EmployeeService service = App.getApp().getServiceManager().get(EmployeeService.class);
		for (int i = 0; i < templates.size(); i++) {
			EmployeeTemplate template = templates.get(i);
			Employee e = new Employee();
			e.setVm(player.getEmployees());
			e.setId(NpcCombatUnit.IDS.incrementAndGet());
			e.setTemplate(template);
			e.setExp(0);
			e.setLevel(100); // 等级100
			e.setQualityLvl(0);
			e.setStarLvl(0);
			e.setEnergy(template.getEnergy());
			e.setState(State.FREE);
//			e.setAttrs(new float[CombatAttribute.Type.length()]);
			e.doInit(service.configure());
//			e.setCreateTime(new Date(TimeUpdater.getInstance().now()));
			employees.add(e);
		}
	}
	
	private void validate() throws CombatException {
		if (stage.getId() == StageTemplate.FRESH_TEMPLATE.getId()) { // 新手引导关卡不用检测
			return;
		}
		int levelLimit = stage.getTemplate().getLevelLimit();
		if (levelLimit < GameStaticConfig.pveStageOpenLvl) {
			levelLimit = GameStaticConfig.pveStageOpenLvl;
		}
		if (player.getLevel() < levelLimit) {
			throw new CombatException(MessageFormat.format(MessageConst.PVE_STAGE_LEVEL_LIMIT, levelLimit));
		}
		if (stage.getLeftTimes(player) == 0) {
			throw new CombatException(MessageConst.PVE_STAGE_NO_LEFT_TIMES);
		}
		if (player.getVigour() < stage.getTemplate().getCostStr()) {
			throw new CombatException(MessageConst.VIGOUR_NOT_ENOUGH);
		}
		// 检测员工状态、精力
		for (int i = 0; i < employees.size(); i++) {
			Employee e = employees.get(i);
			if (e != null) {
				com.xcity.db.entity.Employee.State state = com.xcity.db.entity.Employee.State.IN_FORMATION;
				if (state.enable && e.getState() != state) {
					throw new CombatException(MessageConst.EMPLOYEE_COMBAT_STATE_ERROR);
				}
//				if (e.getEnergy() < 1) {
//					throw new CombatException(MessageFormat.format(MessageConst.EMPLOYEE_ENERGY_NOT_ENOUGH, e.getName()));
//				}
			}
		}
		// 扣除玩家体力、员工精力
		if (stage.getTemplate().getCostStr() > 0 && !player.decVigour(stage.getTemplate().getCostStr(), Cause.PVE_FIGHT)) {
//			session.send(new HintResponse(req.getSerial(), MessageConst.STR_NOT_ENOUGH));
		}
//		for (int i = 0; i < employees.size(); i++) {
//			Employee e = employees.get(i);
//			if (e != null) {
//				e.decEnergy(1, Cause.PVE_FIGHT);
//			}
//		}
	}
	
	@Override
	public void prepareCombat(Session session, CombatInfoRequest packet) throws CombatException {
		player = session.getClient();
		init(packet.getPVEStageId());
		
		TeamBuilder playerTeamBuilder = new TeamBuilder().setLeader(player);//.setCombatPower(CombatUtils.calcCombatPowerWithEmployees(player));
		for (int i = 0; i < employees.size(); i++) {
			playerTeamBuilder.addMember(employees.get(i));
		}
		
		TeamBuilder npcTeamBuilder = new TeamBuilder();
		NpcTemplate npcLeader = stage.getTemplate().getBoss();
		npcTeamBuilder.setLeader(npcLeader);
		NpcTemplate[] npcs = stage.getTemplate().getNpcs();
		for (int i = 0, len = npcs.length; i < len; i++) {
			npcTeamBuilder.addMember(npcs[i]);
		}
		
		Packet res = new CombatInfoResponse(packet.getSerial(), playerTeamBuilder.build(), npcTeamBuilder.build(), Formation.TYPE_NORMAL);
		session.send(res);
	}
	
	@Override
	public CombatResponse create(CombatService service, Type type, Session session, Packet packet) throws CombatException {
		CombatPVERequest req = (CombatPVERequest) packet;
		player = session.getClient();
		init(req.getId());
		validate();
		
//		PVECombatBuilder builder = new PVECombatBuilder()
//				.setPlayer(player)
//				.setEmployees(employees)
//				.setBossNpc(stage.getTemplate().getBoss())
//				.setListener(this);
		DefaultCombatBuilder builder = new DefaultCombatBuilder()
				.setType(Combat.Type.PVE)
				.setListener(this)
				.setSourceLeader(player)
				.addSourceMembers(employees);
		NpcTemplate boss = stage.getTemplate().getBoss();
		builder.setDestLeader(boss != null ? boss.toCombatabale() : null);
		NpcTemplate[] npcs = stage.getTemplate().getNpcs();
		for (int i = 0; i < npcs.length; i++) {
			NpcTemplate npc = npcs[i];
			builder.addDestMember(npc != null ? npc.toCombatabale() : null);
		}
		App.getApp().getEventManager().addEvent(GameEvents.EVENT_USE_SYSTEM, player, ISystem.SYS_PVE_STAGE, 1);
		LOG.info("[PVE]ID[{}]STAGE[{}]", player.getId(), stage.getId());
		this.creatTime = TimeUpdater.getInstance().now();
		return new CombatResponse(req.getSerial(), builder.build());
	}

	@Override
	public void end(Combat combat, boolean notify) {
//		state = BattleState.END;
//		int star = settle(req);
//		stage.end(star);
//		returnStrIfFail(star);
		Result ref = null;
		long endTime = TimeUpdater.getInstance().now();
		CombatEndPush push = new CombatEndPush(Combat.FAIL, Combat.Type.PVE, combat.getId());
		if (combat.isWinner(player.getId())) {
			int starDetail = calcStar(combat, endTime);
			int star = stage.getGotStar(starDetail);
			List<Drop> drops = Collections.emptyList();
			float addedRatio = 0f;
			List<Drop> allDrops = stage.getStar() == 0? stage.getTemplate().getPassRewardsDrop()[star - 1] : stage.getTemplate().getRewardsDrop();
//			List<Drop> itemDrops = new ArrayList<Drop>(allDrops.size());
			drops = new ArrayList<Drop>(allDrops.size());
			List<PVEStageDropListener> listenerList = new ArrayList<PVEStageDropListener>();
			PVEUtils.calcPVEStageDrop(player, employees, stage, drops, allDrops, addedRatio, 1, listenerList, Cause.PVE_END);
////--------------------------------
//			int employeeSize = sizeOf(employees);
////			// 收入加成技能
////			addedRatio = ((PlayerBattler) getSource()).batchCalcFloat(SkillGroups2.RAISE_REWARD_EXP_AND_MONEY);
//			for (int i = 0; i < allDrops.size(); i++) {
//				Drop drop = allDrops.get(i);
//				// 经验、物品掉落特殊处理
//				if (employeeSize > 0 && drop instanceof ExpDrop) {
//					int exp = ((ExpDrop) drop).getExp();
//					int expAdded = 0;
//					if (addedRatio > 0) {
//						expAdded = (int) (exp * addedRatio);
//					}
////					int playerGainExp = exp * PVEBattle.PLAYER_GAIN_EXP_PERCENT / GameStaticConfig.percentBase;
////					player.addExp(playerGainExp, Cause.PVE_END);
////					if (expAdded > 0) {
////						player.addExp(expAdded, Cause.EMPLOYEE_SKILL_TRIGGERED);
////					}
//					exp = exp / employeeSize;//(exp - playerGainExp) / employeeSize;
//					for (int j = 0; j < employees.size(); j++) {
//						Employee e = employees.get(j);
//						if (e != null) {
//							e.addExp(exp, Cause.PVE_END);
//							if (expAdded > 0) {
//								e.addExp(expAdded, Cause.EMPLOYEE_SKILL_TRIGGERED);
//							}
//						}
//					}
//					drops.add(drop);
//				} else if (drop instanceof ItemDrop) {
//					itemDrops.add(drop);
//				} else {
//					drop.drop(player, Cause.PVE_END);
//					drops.add(drop);
//					if (addedRatio > 0 && drop instanceof GoldDrop) {
//						int gold = (int) (((GoldDrop) drop).getGold() * addedRatio);
//						player.addGold(gold, Cause.EMPLOYEE_SKILL_TRIGGERED);
//					}
//				}
//			}
//			// 物品最多只掉落8组
//			CommonUtils.shuffle(itemDrops);
//			for (int i = 0, size = PVEBattle.MAX_DROP_ITEM_SIZE < itemDrops.size() ? PVEBattle.MAX_DROP_ITEM_SIZE : itemDrops.size(); i < size; i++) {
//				Drop drop = itemDrops.get(i);
//				if (drop.drop(player, Cause.PVE_END)) {
//					drops.add(drop);
//				}
//			}
//			// 处理npc掉落
//			NpcTemplate[] npcs = stage.getTemplate().getNpcs();
//			for (int i = 0; i < npcs.length; i++) {
//				boolean succ = processNpcDrop(npcs[i], player, drops);
//				if (succ) { // 小怪只掉一次
//					break;
//				}
//			}
//			processNpcDrop(stage.getTemplate().getBoss(), player, drops);
////--------------------------------
			
			boolean isFirstPass = stage.getPassTime() == 0;
			// 累计副本星数（货币）
			int c = star - stage.getStar();
			if (c > 0) {
				player.addStageStars(c, Cause.PVE_END);
			}
			stage.end(star);
//			PVEStageResultResponse res = new PVEStageResultResponse(req.getSerial(), req.getId(), 1, drops, addedRatio);
//			player.send(res);
			App.getApp().getEventManager().addEvent(GameEvents.EVENT_PVE_SUCCESS, player, stage, star, drops, isFirstPass);
			ref = new Result(player, stage, starDetail, listenerList, addedRatio);
			push.setResult(Combat.SUCC);
			push.setRef(ref);
		} else {
			ref = new Result(player, stage, 0);
//			player.addStrength(stage.getTemplate().getCostStr(), Cause.PVE_FAIL);
			player.addVigour(stage.getTemplate().getCostStr(), Cause.PVE_FAIL);
		}
		if (notify) {
			player.send(push);
		}
		LOG.info("[PVE END]ID[{}]STAGE[{}]RESULT[{}]", player.getId(), stage.getId(), ref.star);
	}
	
	@SuppressWarnings("unused")
	private static boolean processNpcDrop(NpcTemplate npc, Player player, final List<Drop> result) {
		if (npc == null) {
			return false;
		}
		DropGroupTemplate t = App.getApp().getServiceManager().get(TemplateService.class).get(DropGroupTemplate.class, npc.getDropGropId());
		if (t == null) {
			return false;
		}
		t.getDrop().drop(Drop.RND, player, Cause.PVE_END, new ItemDropListener() {
			@Override
			public void itemDroped(Player player, int itemId, int count) {
				result.add(new ItemDrop(0, itemId, count));
			}
		});
		return true;
	}

	@SuppressWarnings("unused")
	private static int sizeOf(List<Employee> employees) {
		int c = 0;
		for (int i = 0; i < employees.size(); i++) {
			if (employees.get(i) != null) {
				c++;
			}
		}
		return c;
	}
	
	static class Result {
		public int id; // 关卡id
		public int star; // 星级 0:未通过/失败;1~3:挑战成功(1~3星)
		public byte boxState; //宝箱状态(0:无宝箱 1:未通关不可领 2:通关可领 3:已领取)
//		public DropInfoV2 rewards = DropInfoV2.EMPTY; // 获得的奖励
		public RewardInfo rewards = RewardInfo.EMPTY;
		public StageSimple next; // 下一关卡信息
		public List<StarInfo> starInfoList;
		public int nextHeroId;//后置英雄关ID -1:没有
		public int nextHeroState;//后置英雄关状态  0:未解锁 1:解锁

		public Result(Player player, PVEStage stage, int starDetail) {
			this(player, stage, starDetail, null, 0f);
		}
		
		public Result(Player player, PVEStage stage, int starDetail, /*List<Drop> drops*/List<PVEStageDropListener> list, float addedRatio) {
			this.id = stage.getId();
			this.star = stage.getStar();
			this.boxState = stage.getStageBoxState();
//			this.rewards = drops != null ? new DropInfoV2(drops, addedRatio) : DropInfoV2.EMPTY;
			this.rewards = list != null && list.size() > 0? new RewardInfo(list.get(0)) : RewardInfo.EMPTY;
			PVEStage nextStage = player.getPveStages().findNextStage(stage);
			this.next = nextStage != null ? new StageSimple(player, nextStage) : null;

			this.starInfoList = new ArrayList<StarInfo>(3);
			for(int i = 0; i < StageTemplate.CONDITION_COUNT + 1; i++){
				if((stage.getTemplate().getFullStar() & (1 << i)) > 0){
					String str = "";
					switch(i){
						case 0:
							str = MessageConst.PVE_STAR_WIN;
							break;
						case 1:
							str = MessageFormat.format(MessageConst.PVE_STAR_TIME, stage.getTemplate().getTimeLimit());
							break;
						case 2:
							str = MessageFormat.format(MessageConst.PVE_STAR_ROUND, stage.getTemplate().getRoundStar());
							break;
						case 3:
							if(stage.getTemplate().getDeathStar() == 1){
								str = MessageFormat.format(MessageConst.PVE_STAR_NO_DEATH, stage.getTemplate().getDeathStar());
							}else{
								str = MessageFormat.format(MessageConst.PVE_STAR_DEATH, stage.getTemplate().getDeathStar());
							}
							break;
						case 4:
							str = MessageFormat.format(MessageConst.PVE_STAR_HP, stage.getTemplate().getHpStar());
							break;
					}
					StarInfo info = new StarInfo(str, (starDetail & (1 << i)) > 0? 1 : 0, i);
					this.starInfoList.add(info);
				}
			}
			Collections.sort(this.starInfoList);
			int nextHeroId = -1;
			int nextHeroState = -1;
			if(stage.getTemplate().getType() != PVEManager.STAGE_TYPE_HERO){
				int page = stage.getTemplate().getPage() - 1;
				List<PVEStage> normalList = player.getPveStages().getStages(page, 0);
				if(stage.getSubIndex() == normalList.size() - 1){
					//本页最后一关
					List<PVEStage> heroList = player.getPveStages().getStages(page, 1);
					nextHeroId = heroList.get(0).getId();
					nextHeroState = player.getPveStages().getLockStateByStage(heroList.get(0));
				}
			}
			this.nextHeroId = nextHeroId;
			this.nextHeroState = nextHeroState;
		}
	}
	
	static class StageSimple {
		public int id;
		public byte state; // 0: 未解锁, 1: 已解锁
		public int levelLimit;
		public StageSimple(Player player, PVEStage ref) {
			this.id = ref.getId();
			PVEStage previous;
//			this.state = (byte) (player.getLevel() >= ref.getTemplate().getLevelLimit()
//					&& ((previous = player.getPveStages().findPreviousStage(ref)) == null || previous.isPass())
//					? 1 : 0);
			//2017.06.26此状态不判断等级 客户端自行判断等级
			this.state = (byte) (((previous = player.getPveStages().findPreviousStage(ref)) == null || previous.isPass())? 1 : 0);
			this.levelLimit = ref.getTemplate().getLevelLimit();
		}
	}
	
	/**
	 * starDetail 时间 1<<1  回合数1<<2 死亡数量1<<3 剩余血量1<<4
	 * @param combat
	 * @param endTime
	 * @return
	 */
	public int calcStar(Combat combat, long endTime){
//		int star = 3;
		int starDetail = 1;
		CombatUnit unit = combat.find(player.getId());
		if(unit == null){
			return 1;
		}
		CombatTeam team = unit.getTeam();
		List<CombatUnit> unitList = team.all();
		int totalHp = 0;
		int maxTotalHp = 0;
		int deathCount = 0;
		for(int i = unitList.size() - 1; i >= 0; i--){
			CombatUnit u = unitList.get(i);
			totalHp += u.getHp();
			maxTotalHp += u.getMaxHp();
			if(u.isDied() && u.getMaxHp() > 0){
				deathCount++;
			}
		}
		//血量
		int hpCond = stage.getTemplate().getHpStar();
		if(hpCond != 0){
			int percent = (totalHp + 5) * 1000 / maxTotalHp;
			if(percent < hpCond * 10){
//				star--;
			}else{
				starDetail = starDetail | (1 << 4);
			}
		}
		//死亡
		int deathCond = stage.getTemplate().getDeathStar();
		if(deathCond != -1){
			if(deathCount >= deathCond){
//				star--;
			}else{
				starDetail = starDetail | (1 << 3);
			}
		}
		//回合数
		int roundCond = stage.getTemplate().getRoundStar();
		if(roundCond > 0){
			if(roundCond < combat.roundCount()){
//				star--;
			}else{
				starDetail = starDetail | (1 << 2);
			}
		}
		//时间 
		int second = stage.getTemplate().getTimeLimit();
		if(second != 0){
			long elapse = endTime - creatTime;
			if(elapse > second * 1000L){
//				star--;
			}else{
				starDetail = starDetail | (1 << 1);
			}
		}
		if(starDetail < 1){
			starDetail = 1;
		}
		return starDetail;
	}

	@Override
	public void roundStart(Round round) {
	}

	@Override
	public void roundEnd(Round round) {
	}

}
